const getPaymentUrl = require("./config").getPaymentUrl;
const leftPad = require("./left-pad");

function createmsgId() {
  return (
    Math.random()
      .toString(36)
      .substring(2, 15) +
    Math.random()
      .toString(36)
      .substring(2, 15)
  );
}

function formateDateNum(num) {
  return Number(num) < 10 ? "0" + num : "" + num;
}

function getMerTransTime() {
  let date = new Date();
  let year = formateDateNum(date.getFullYear());
  let month = formateDateNum(date.getMonth() + 1);
  let day = formateDateNum(date.getDate());
  let hour = formateDateNum(date.getHours());
  let minute = formateDateNum(date.getMinutes());
  let second = formateDateNum(date.getSeconds());
  let timeZone =
    "+" +
    date
      .toTimeString()
      .split(" ")[1]
      .split("+")[1];
  return year + month + day + hour + minute + second + timeZone;
}

// 生成下单额外参数  msgId paymentBrand tradeFrom merTransTime
function getExtralParams() {
  let msgId = createmsgId();
  let merTransTime = getMerTransTime();
  return {
    msgId,
    merTransTime,
    paymentBrand: "WXP",
    tradeFrom: "mis"
  };
}

/**
 * 生成订单号
 *
 * @param {*} merchantId 商户号
 */
function produceOrderNum(merchantId) {
  const today = new Date();
  const YEAR = today
    .getFullYear()
    .toString()
    .slice(2);
  const MONTH = today.getMonth() + 1;
  const DATE = today.getDate();
  let orderNum = `${merchantId}${YEAR}${MONTH}${DATE}`;
  const length = 32 - orderNum.length;
  const randomNum = Math.random()
    .toString()
    .substr(2, length);
  return orderNum + randomNum;
}

function isNumber(value) {
  if (typeof value === "number") {
    return true;
  }
  if (!isNaN(value)) {
    return true;
  }
  return false;
}

function getObjByKeys(source, keys) {
  let obj = {};
  keys.forEach(key => {
    if (source[key]) {
      obj[key] = source[key];
    }
  });
  return obj;
}

/**
 *  自定义的请求方法
 *
 * @param {*} agent wechat or ali
 * @param {*} params 请求参数
 */
function myRequest(params) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...params,
      success: resolve,
      fail: reject
    });
  });
}

/**
 * login方法，兼容wx & ali
 * @param {*} agent  wx or ali
 */
function login(agent) {
  return new Promise((resolve, reject) => {
    wx.login({
      success: res => {
        let { code } = res;
        resolve(code);
      },
      fail: reject
    });
  });
}

// check goodsList格式
function checkRest(rest) {
  if (Object.keys(rest).includes("goodsList")) {
    let goodsList = rest.goodsList;
    try {
      goodsList = JSON.parse(goodsList);
    } catch (error) {
      throw new Error("goodsList JSON parse fail");
    }
    if (!Array.isArray(goodsList)) {
      throw new Error("goodsList type error");
      return;
    }
    goodsList.forEach(good => {
      ["goodsId", "goodsName", "goodsNum", "price"].forEach(key => {
        if (good[key] === undefined) {
          throw new Error("goodsList ===>" + key + " need");
        }
      });
    });
  }
}

function requestPayment({
  sid,
  orderNum,
  transCurrency,
  appId,
  backUrl,
  transAmt,
  callbackObj,
  ...rest
}) {
  // 回调
  let callbackSuccess, callbackFail, callbackComplete;
  try {
  
    const noop = function() {};
    callbackSuccess = (callbackObj && callbackObj.success) || noop;
    callbackFail = (callbackObj && callbackObj.fail) || noop;
    callbackComplete = (callbackObj && callbackObj.complete) || noop;
    sid = sid ? sid.trim() : "";
    orderNum = orderNum ? orderNum.trim() : "";
    transCurrency = transCurrency ? transCurrency.trim() : "";
    appId = appId ? appId.trim() : "";
    backUrl = backUrl ? backUrl.trim() : "";
    transAmt = transAmt ? transAmt.trim() : "";

    console.log("transCurrency",transCurrency,appId);

    // 对rest过滤空字符
    for (let key in rest) {
      if (!rest[key]) {
        delete rest[key];
      } else {
        rest[key] =
          typeof rest[key] === "string" ? rest[key].trim() : rest[key];
      }
    }

    if (!sid) throw new Error("need sid");
    if (!transCurrency) throw new Error("need transCurrency");
    if (!transAmt) throw new Error("need transAmt");
    if (!orderNum) throw new Error("need orderNum");
    if (!appId) throw new Error("need appid");
    if (!backUrl) throw new Error("need backUrl");
    if (!callbackObj) throw new Error("need callbackObj");

    checkRest(rest);
    // transAmt: 支付金额，单位-分，货币-人民币;
    transAmt = Number(transAmt);
    if (isNumber(transAmt) && transAmt >= 1) {
      transAmt = leftPad(transAmt.toFixed(2).replace(".", ""), 12, "0");
    } else {
      throw new Error("transAmt type error!");
    }
    // handle
    login().then(code => {
 
      let reqData = { orderNum, sid, appId, backUrl, transAmt, transCurrency, code };
      reqData = Object.assign({ ...rest }, reqData, getExtralParams());
      myRequest({
        url: getPaymentUrl("mer", sid),
        method: "POST",
        data: reqData
      })
        .then(res => {
          if (res.statusCode === 200) {
            if (res.data.respCode === "09") {
              let { payjson } = res.data;
              wx.requestPayment({
                timeStamp: payjson.chooseWXPay.timeStamp,
                nonceStr: payjson.chooseWXPay.nonceStr,
                package: payjson.chooseWXPay.package,
                signType: payjson.chooseWXPay.signType,
                paySign: payjson.chooseWXPay.paySign,
                success: function(result) {
                  callbackSuccess(
                    Object.assign({}, result, {
                      sdkMsg: getObjByKeys(res, [
                        "orderNum",
                        "transAmt",
                        "transCurrency",
                        "merTransTime",
                        "merTransTime"
                      ])
                    })
                  );
                },
                fail: callbackFail,
                complete: callbackComplete
              });
            } else {
              callbackFail({ errMsg: res.data.errorDetail });
              callbackComplete();
              console.error("sdk throw error: unified fail " + res.data.errorDetail);
            }
          } else {
            callbackFail({ errMsg: res.data.errorDetail || res.data});
            callbackComplete();
            console.error("sdk throw error: unified fail " + (res.data.errorDetail || res.data));
          }
        })
        .catch(error => {
          callbackFail({
            errMsg: "sdk throw error: " + JSON.stringify(error)
          });
          callbackComplete();
        });
    });
  } catch (error) {
    console.error("sdk throw error", error);
    callbackFail({
      errMsg: "sdk throw error: " + error.message
    });
    callbackComplete();
  }
}

module.exports = requestPayment;

